package security.filters;

import framework.config.SecurityConfig;
import framework.utils.RequestUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import security.defined.AuthenticationCheckerResult;
import security.error.AuthenticationCheckerException;
import security.service.SecurityContext;
import security.utils.SecurityAuthUtil;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
public class AuthenticationServletFilter extends AuthenticationBase implements Filter {

    public AuthenticationServletFilter(SecurityContext securityContext) {
        super(securityContext);
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
        if (getSecurityConfig().getEnable()) {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) resp;
            AuthenticationData data;
            try {
                data = this.authCheck(this.createAuthenticationHandler(request, response, filterChain, getSecurityConfig()));
            } catch (AuthenticationCheckerException authenticationCheckerException) {
                if (AuthenticationCheckerResult.NO_AUTH.equals(authenticationCheckerException.getStatus())) {
                    if (StringUtils.hasText(getSecurityConfig().getRedirectOnNoAuth())) {
                        // 输导异常页面
                        response.sendRedirect(getSecurityConfig().getRedirectOnNoAuth());
                    } else {
                        // 输出异常信息
                        response.sendError(401, RequestUtil.getMessageDefault("error.e401", "Unauthorized"));
                    }
                } else if (AuthenticationCheckerResult.NO_PERMISSION.equals(authenticationCheckerException.getStatus())) {
                    if (StringUtils.hasText(getSecurityConfig().getRedirectOnNoPermission())) {
                        // 输导异常页面
                        response.sendRedirect(getSecurityConfig().getRedirectOnNoPermission());
                    } else {
                        // 输出异常信息
                        response.sendError(405, RequestUtil.getMessageDefault("error.e405", "No permission"));
                    }
                } else {
                    if (StringUtils.hasText(getSecurityConfig().getRedirectOnAuthError())) {
                        // 输导异常页面
                        response.sendRedirect(getSecurityConfig().getRedirectOnAuthError());
                    } else {
                        // 输出异常信息
                        response.sendError(500, authenticationCheckerException.getMessage());
                    }
                }
                return;
            } catch (Throwable throwable) {
                // 验证异常
                log.error("Authentication valid error," + throwable.getMessage(), throwable);
                if (StringUtils.hasText(getSecurityConfig().getRedirectOnAuthError())) {
                    // 输导异常页面
                    response.sendRedirect(getSecurityConfig().getRedirectOnAuthError());
                } else {
                    // 输出异常信息
                    response.sendError(401, throwable.getMessage());
                }
                return;
            }
            // set context
            if (data != null) {
                SecurityAuthUtil.authorized(data);
                filterChain.doFilter(req, resp);
            } else {
                response.sendError(401, "Unauthorized of server error");
            }
        } else {
            filterChain.doFilter(req, resp);
        }
    }

    /**
     * 创建授权处理器
     *
     * @param request
     * @param response
     * @param filterChain
     * @param securityConfig
     * @return
     */
    protected AuthenticationHandler createAuthenticationHandler(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain, SecurityConfig securityConfig) {
        return new AuthenticationServletHandler(request, response, filterChain, getSecurityConfig());
    }

}
